#include <iterator>
#include <unistd.h>
#include "MarkupSTL.h"
#include "global.h"
#include "cmd.h"
#include "Game.h"
#include "RedisClient.h"
#include "Logic.h"
#include "json.h"
#include "globalExtern.h"
#include "Host.h"
#include "util.h"
#include "2850_gamerecord.pb.h"

CGameServer::CGameServer()
{
}

CGameServer::~CGameServer()
{
}


bool CGameServer::InitGame()
{

	return true;
}

int CGameServer::OnBYTimeOut(int Timerid)
{
	switch (Timerid)
	{
	case TIMERID_CACHE_CHECK:
	{
		procTimerCacheCheck();
		break;
	}
	case TIMERID_DETAIL_CACHE_CHECK:
	{
		procTimerDetailCacheCheck();
		break;
	}
	default:
		break;
	}
	return 0;
}

int CGameServer::ProcessPacket(SocketHandler * pHandler, NETInputPacket* inputPkg)
{
	unsigned int cmd = inputPkg->GetCmdType();
	switch (cmd)
	{
	case gamerecord::GAMERECORD_CMD_RECORD_CACHE_PUSH:
	{
		ProcRecordCachePush(pHandler, inputPkg);
		break;
	}
	case gamerecord::GAMERECORD_CMD_GET_RECORD_REQ:
	{
		ProcGetGameRecord(pHandler, inputPkg);
		break;
	}
	case gamerecord::GAMERECORD_CMD_GET_DETAIL_REQ:
	{
		ProcGetGameRecordDetail(pHandler, inputPkg);
		break;
	}
	default:
		break;
	}

	return 0;
}

int CGameServer::ProcRecordCachePush(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	gamerecord::GameRecordDataCache msg;
	if (!inputPkg->parsePb(&msg))
	{
		log_error("flowcache parse err");
		return -1;
	}


	unsigned int uid = msg.uid();
	unsigned int game =  msg.game();
	if (0 == uid || 0 == game)
	{
		log_error("wrong param,uid,%u,game,%u", uid, game);
	    return 1;
	}

	unsigned int recordcount = msg.recordcount();
	_u64_ cacheindex = msg.cacheindex();
	if (0 == recordcount || 0 == cacheindex) 
	{
		log_error("wrong param,uid:%u,game:%u,roundid,%s",uid, game, msg.roundid().c_str());
		return 1;
	}

    time_t tt = ::time(NULL);
	_u64_ rtime = msg.timestamp();
	if (0 == rtime)
		rtime = tt;

    std::map<unsigned int, stRecordCache>& gamerecordcache = m_recordcache[game];
	std::map<unsigned int, stRecordCache>::iterator itor = gamerecordcache.find(uid);
	if (gamerecordcache.end() == itor)
	{
		stRecordCache cache;
		std::pair<std::map<unsigned int, stRecordCache>::iterator, bool> ret = gamerecordcache.emplace(uid, cache); 
		if (ret.second)
			itor = ret.first;
		else
		{
			log_error("map insert err,uid,%u", uid);
			return 2;
		}
	}

	log_debug("ProcRecordCachePush item,cacheindex:%llu,uid:%u,roundid:%s,bet:%lld,betact:%d,win:%lld,winact:%d,time:%llu,daybetamount,%lld,daywinamount,%lld,firstofdayflag,%d, recordcount:%u,timezoneinmin,%d"
		, cacheindex, uid, msg.roundid().c_str(), msg.bet(), msg.betact(), msg.win(), msg.winact(), rtime, msg.daybetamount(), msg.daywinamount(), msg.firstofdayflag(), recordcount, msg.timezoneinmin());

	itor->second.m_lastflow.emplace(cacheindex
	, stRecordItem(std::move(msg.roundid()), msg.bet(), msg.betact(), msg.win(), msg.winact(), rtime
	, std::move(msg.detail()), msg.daybetamount(), msg.daywinamount(),msg.firstofdayflag(), recordcount, tt, std::move(msg.ext())));
	if (recordcount > itor->second.m_count)
		itor->second.m_count = recordcount;
	itor->second.m_timezoneinmin = msg.timezoneinmin();
	itor->second.m_lastflowtime = tt;

    unsigned int ymd;
	timestampToymd(rtime, itor->second.m_timezoneinmin, ymd);
    std::map<unsigned int, stRecordDayInfo>::iterator itor1 = itor->second.m_dayinfo.find(ymd);
	if (itor->second.m_dayinfo.end() == itor1)
	{
		itor->second.m_dayinfo.emplace(ymd, stRecordDayInfo(msg.daybetamount(), msg.daywinamount(), recordcount));
	}
	else
	{
		if (recordcount > itor1->second.m_userseq)
		{
			itor1->second.m_daybetamount = msg.daybetamount();
			itor1->second.m_daywinamount = msg.daywinamount();
			itor1->second.m_userseq = recordcount;
		}
	}
	
	if (itor->second.m_lastflow.size() > g_flow_cache_num && tt - itor->second.m_lastfetchtime >= g_cache_exp_full_dur)
    {
		while (itor->second.m_lastflow.size() > g_flow_cache_num)
		{
			itor->second.m_lastflow.erase(itor->second.m_lastflow.begin());
		}
		
    }

	if (itor->second.m_dayinfo.size() > g_day_cache_num && tt - itor->second.m_lastfetchtime >= g_cache_exp_full_dur)
	{
		while (itor->second.m_dayinfo.size() > g_day_cache_num)
		{
			itor->second.m_dayinfo.erase(itor->second.m_dayinfo.begin());
		}

	}
	return 0;
}

int CGameServer::ProcGetGameRecord(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	gamerecord::GameRecordReq msg;
	if (!inputPkg->parsePb(&msg))
	{
		log_error("parse pb fail");
		return 1;
	}

	unsigned int uid = msg.uid();
	unsigned int game = msg.game();
	gamerecord::GameRecordResp rsp;
	do 
	{
		if (0 == uid || 0 == game)
		{
			rsp.set_result(1);
			break;
		}
        rsp.set_uid(uid);
		rsp.set_game(game);

        std::map<unsigned int, stRecordCache>& gamerecordcache = m_recordcache[game];
		std::map<unsigned int, stRecordCache>::iterator itor = gamerecordcache.find(uid);
		if (gamerecordcache.end() == itor)
		{
			std::string gamerecordcountname;
			gamerecordCountTable(game, g_record_count_mod, uid, gamerecordcountname);
	        if(m_gamerecordcounttables.end() == m_gamerecordcounttables.find(gamerecordcountname))
	        {
		        if (!m_dbHandlerAssistant.createGameRecordCountTable(gamerecordcountname))
		        {
			        log_error("create gamerecord count table fail,%s", gamerecordcountname.c_str());
			        rsp.set_result(3);
			        break;
		        }
		
		        m_gamerecordcounttables.emplace(gamerecordcountname);
	        }

			stRecordCache cache;
			unsigned int count = 0;
			int timezoneinmin = 0;
			int flag = 0;
			if (m_dbHandlerAssistant.getUserRecordCount(gamerecordcountname, uid, g_record_count_mod, count, timezoneinmin, flag))
			{
				cache.m_count = count;
				cache.m_timezoneinmin = timezoneinmin;
				std::pair<std::map<unsigned int, stRecordCache>::iterator, bool> ret = gamerecordcache.emplace(uid, cache);
				if (!ret.second)
				{
					rsp.set_result(3);
					break;
				}
				itor = ret.first;

				if (flag > 0)
				{
					//m_dbHandlerAssistant.insertAndaddUserRecordCount(uid, g_record_count_mod, 0);
				}

			}
			else
			{
				rsp.set_result(2);
				break;
			}
		}

		time_t tt = ::time(NULL);
		itor->second.m_lastfetchtime = tt;

		if (0 == itor->second.m_count)
		{
			rsp.set_result(0);
			rsp.set_endflag(1);
			break;
		}
		else
		{
			std::string ym;
			unsigned int mindex = 0;
			_u64_ seq = 0;
			unsigned int minuseq = 0;

			rsp.set_timezoneinmin(itor->second.m_timezoneinmin);
            _u64_ recentlisttp = calcRecentDayPoint(tt, g_list_recent_days, itor->second.m_timezoneinmin);

			std::set<unsigned int> dayset;
			if (itor->second.m_lastflow.size() > 0)
			{
				std::map<_u64_, stRecordItem>::const_iterator itor1 = itor->second.m_lastflow.begin();
				_u64_ index = itor1->first;

				if (0 == msg.pos())
				{
					if (msg.size() <= itor->second.m_lastflow.size())
					{
						std::map<_u64_, stRecordItem>::reverse_iterator itorend = itor->second.m_lastflow.rbegin();
						::advance(itorend, msg.size());
						for (std::map<_u64_, stRecordItem>::reverse_iterator itor3 = itor->second.m_lastflow.rbegin(); itorend != itor3; ++itor3)
						{
							if (itor3->second.m_timestamp < recentlisttp)
							{
								rsp.set_endflag(1);
								break;
							}
							gamerecord::GameRecordResp::GameRecordItem* pitem = rsp.add_list(); 
							
							pitem->set_roundid(itor3->second.m_roundid);
							pitem->set_bet(itor3->second.m_bet);
							pitem->set_betact((gamerecord::BET_ACT)itor3->second.m_betact);
							pitem->set_win(itor3->second.m_win);
							pitem->set_winact((gamerecord::WIN_ACT)itor3->second.m_winact);
							pitem->set_timestamp(itor3->second.m_timestamp);
							pitem->set_firstofdayflag(itor3->second.m_firstofdayflag);
							pitem->set_detail(itor3->second.m_detail);
							pitem->set_id(itor3->first);
							pitem->set_ext(itor3->second.m_ext);
							itor3->second.m_lastdetailcachetime = tt;
							if (1 == itor3->second.m_userseq)
							{
								rsp.set_endflag(1);
							}

							unsigned int ymd = 0;
							timestampToymd(itor3->second.m_timestamp, itor->second.m_timezoneinmin, ymd);
							std::map<unsigned int, stRecordDayInfo>::iterator itor4 = itor->second.m_dayinfo.find(ymd);
							if (itor->second.m_dayinfo.end() == itor4)
							{
							    itor->second.m_dayinfo.emplace(ymd, stRecordDayInfo(itor3->second.m_daybetamount, itor3->second.m_daywinamount, itor3->second.m_userseq));
							}
							else
							{
								 if (itor3->second.m_userseq > itor4->second.m_userseq)
								 {
									 itor4->second.m_daybetamount = itor3->second.m_daybetamount;
									 itor4->second.m_daywinamount = itor3->second.m_daywinamount;
									 itor4->second.m_userseq = itor3->second.m_userseq;
								 }
							}

							dayset.emplace(ymd);
						}
					}
					else
					{
						mindex = (index & 0xFFFF000000000000) >> 48;
						seq = index & 0x0000FFFFFFFFFFFF;
						minuseq = itor1->second.m_userseq;

						int nodataflag = 0;
						int delflag = 0;

                        std::map<unsigned int, std::pair<std::string, int> >& indexm = m_indexm[game];
						std::map<unsigned int, std::pair<std::string, int> >::const_iterator itor2 = indexm.find(mindex);
						if (indexm.end() == itor2)
						{
							std::string monthlisttname;
							monthlistTable(game, monthlisttname); 
	                        if (m_monthlistables.end() == m_monthlistables.find(monthlisttname))
	                        {
		                        if (!m_dbHandlerAssistant.createMonthListTable(monthlisttname))
		                        {
			                        log_error("create monthlist table fail,%s", monthlisttname.c_str());
			                        rsp.set_result(2);
				                    break;
		                        }
		
		                        m_monthlistables.emplace(monthlisttname);
	                        }


							if (m_dbHandlerAssistant.getYmInfoFrommSeq(monthlisttname, mindex, ym, delflag, nodataflag))
							{
								indexm.emplace(mindex, std::make_pair(ym, delflag));
								m_mindex[game][ym] = std::make_pair(mindex, delflag);
							}
							else
							{
								if (1 == nodataflag)
								{
								}
								else
								{
									rsp.set_result(2);
									break;
								}
							}
						}
						else
						{
							ym = itor2->second.first;
							delflag = itor2->second.second;
						}

						unsigned int need = 0;
						if (1 == delflag || 1 == nodataflag)
						{
							rsp.set_result(0);
							rsp.set_endflag(1);
							need = 0;
						}
						else
						{
						    if (msg.size() >= itor->second.m_count)
						    {
							    if (itor->second.m_count < itor->second.m_lastflow.size())
							    {
								    rsp.set_result(3);
								    log_error("error data,uid,%d,count,%u, cachesize,%u", uid, itor->second.m_count, itor->second.m_lastflow.size());
								    break;
							    }
							    else
							    {
								    need = itor->second.m_count - itor->second.m_lastflow.size();
							    }
						    }
						    else
						    {
							    need = msg.size() - itor->second.m_lastflow.size();
						    }
						}


                        std::map<_u64_, stRecordItem> mr;
						unsigned int n = 0;
						if (need > 0)
						{
							int ret = fetchRecord(game, ym, mindex, seq, minuseq, uid, need, tt, mr);
							if (2 == ret)
							{
								rsp.set_result(2);
								break;
							}
							else
							{
								rsp.set_result(0);
								rsp.set_endflag(0);
								if (1 == ret)
								{
									rsp.set_endflag(1);
								}

								if (mr.size() + itor->second.m_lastflow.size() <= g_flow_cache_num)
								{
									itor->second.m_lastflow.insert(mr.begin(), mr.end());
								}
								else
								{
									if (g_flow_cache_num > itor->second.m_lastflow.size())
									{
										n = g_flow_cache_num - itor->second.m_lastflow.size();
										if (mr.size() >= n)
										{
											std::map<_u64_, stRecordItem>::reverse_iterator itorend = mr.rbegin();
											::advance(itorend, n);
											itor->second.m_lastflow.insert(mr.rbegin(), itorend);
										}

									}

								}
							}
						}

						for (std::map<_u64_, stRecordItem>::reverse_iterator itor3 = itor->second.m_lastflow.rbegin(); itor->second.m_lastflow.rend() != itor3; ++itor3)
						{
							if (itor3->second.m_timestamp < recentlisttp)
							{
								rsp.set_endflag(1);
								break;
							}
							gamerecord::GameRecordResp::GameRecordItem* pitem = rsp.add_list(); 
							
							pitem->set_roundid(itor3->second.m_roundid);
							pitem->set_bet(itor3->second.m_bet);
							pitem->set_betact((gamerecord::BET_ACT)itor3->second.m_betact);
							pitem->set_win(itor3->second.m_win);
							pitem->set_winact((gamerecord::WIN_ACT)itor3->second.m_winact);
							pitem->set_timestamp(itor3->second.m_timestamp);
							pitem->set_firstofdayflag(itor3->second.m_firstofdayflag);
							pitem->set_detail(itor3->second.m_detail);
							pitem->set_id(itor3->first);
							pitem->set_ext(itor3->second.m_ext);
							itor3->second.m_lastdetailcachetime = tt;
							if (1 == itor3->second.m_userseq)
							{
								rsp.set_endflag(1);
							}

							unsigned int ymd = 0;
							timestampToymd(itor3->second.m_timestamp, itor->second.m_timezoneinmin, ymd);
							std::map<unsigned int, stRecordDayInfo>::iterator itor4 = itor->second.m_dayinfo.find(ymd);
							if (itor->second.m_dayinfo.end() == itor4)
							{
								itor->second.m_dayinfo.emplace(ymd, stRecordDayInfo(itor3->second.m_daybetamount, itor3->second.m_daywinamount, itor3->second.m_userseq));
							}
							else
							{
								if (itor3->second.m_userseq > itor4->second.m_userseq)
								{
									itor4->second.m_daybetamount = itor3->second.m_daybetamount;
									itor4->second.m_daywinamount = itor3->second.m_daywinamount;
									itor4->second.m_userseq = itor3->second.m_userseq;
								}
							}

							dayset.emplace(ymd);
						}
						if (mr.size() > 0 && n > 0)
						{
							std::map<_u64_, stRecordItem>::reverse_iterator itorbegin = mr.rbegin();
							::advance(itorbegin, n);
							for (; mr.rend() != itorbegin; ++itorbegin)
							{
								if (itorbegin->second.m_timestamp < recentlisttp)
							    {
								    rsp.set_endflag(1);
								    break;
							    }
								gamerecord::GameRecordResp::GameRecordItem* pitem = rsp.add_list(); 

								pitem->set_roundid(itorbegin->second.m_roundid);
							    pitem->set_bet(itorbegin->second.m_bet);
							    pitem->set_betact((gamerecord::BET_ACT)itorbegin->second.m_betact);
							    pitem->set_win(itorbegin->second.m_win);
							    pitem->set_winact((gamerecord::WIN_ACT)itorbegin->second.m_winact);
							    pitem->set_timestamp(itorbegin->second.m_timestamp);
							    pitem->set_firstofdayflag(itorbegin->second.m_firstofdayflag);
							    pitem->set_detail(itorbegin->second.m_detail);
							    pitem->set_id(itorbegin->first);
								pitem->set_ext(itorbegin->second.m_ext);

								unsigned int ymd = 0;
								timestampToymd(itorbegin->second.m_timestamp, itor->second.m_timezoneinmin, ymd);
								std::map<unsigned int, stRecordDayInfo>::iterator itor4 = itor->second.m_dayinfo.find(ymd);
								if (itor->second.m_dayinfo.end() == itor4)
								{
									itor->second.m_dayinfo.emplace(ymd, stRecordDayInfo(itorbegin->second.m_daybetamount, itorbegin->second.m_daywinamount, itorbegin->second.m_userseq));
								}
								else
								{
									if (itorbegin->second.m_userseq > itor4->second.m_userseq)
									{
										itor4->second.m_daybetamount = itorbegin->second.m_daybetamount;
										itor4->second.m_daywinamount = itorbegin->second.m_daywinamount;
										itor4->second.m_userseq = itorbegin->second.m_userseq;
									}
								}

								dayset.emplace(ymd);
							}
						}
					}
				}
				else
				{
					_u64_ indexpos = msg.pos();

					std::map<_u64_, stRecordItem> mr;
					if (msg.pos() < index)
					{
						mindex = (indexpos & 0xFFFF000000000000) >> 48;
						seq = indexpos & 0x0000FFFFFFFFFFFF;

						int nodataflag = 0;
						int delflag = 0;

						std::map<unsigned int, std::pair<std::string, int> >& indexm = m_indexm[game];
						std::map<unsigned int, std::pair<std::string, int> >::const_iterator itor2 = indexm.find(mindex);
						if (indexm.end() == itor2)
						{
							std::string monthlisttname;
							monthlistTable(game, monthlisttname);
							if (m_monthlistables.end() == m_monthlistables.find(monthlisttname))
							{
								if (!m_dbHandlerAssistant.createMonthListTable(monthlisttname))
								{
									log_error("create monthlist table fail,%s", monthlisttname.c_str());
									rsp.set_result(2);
									break;
								}

								m_monthlistables.emplace(monthlisttname);
							}


							if (m_dbHandlerAssistant.getYmInfoFrommSeq(monthlisttname, mindex, ym, delflag, nodataflag))
							{
								indexm.emplace(mindex, std::make_pair(ym, delflag));
								m_mindex[game][ym] = std::make_pair(mindex, delflag);
							}
							else
							{
								if (1 == nodataflag)
								{
									ym = "";
								}
								else
								{
									rsp.set_result(2);
									break;
								}
							}
						}
						else
						{
							ym = itor2->second.first;
							delflag = itor2->second.second;
						}

						unsigned int need = 0;
						if (1 == delflag)
						{
							rsp.set_result(0);
							rsp.set_endflag(1);
							need = 0;
						}
						else
						{
							need = msg.size();
						}

						if (need > 0)
						{
							int ret = fetchRecord(game, ym, mindex, seq, itor->second.m_count, uid, need, tt, mr);
							if (2 == ret)
							{
								rsp.set_result(2);
								break;
							}
							else
							{
								rsp.set_result(0);
								if (1 == ret)
								{
									rsp.set_endflag(1);
								}
							}
						}
					}
					else
					{
						std::map<_u64_, stRecordItem>::iterator itor4 = itor->second.m_lastflow.find(indexpos);
						if (itor->second.m_lastflow.end() == itor4)
						{
							rsp.set_result(1);
							break;
						}
						else
						{
							//minuseq = itor4->second.m_userseq;
							unsigned int dis = ::distance(itor4, itor->second.m_lastflow.end());
							unsigned int num = itor->second.m_lastflow.size() - dis;
							if (num < msg.size())
							{
								mindex = (index & 0xFFFF000000000000) >> 48;
								seq = index & 0x0000FFFFFFFFFFFF;

								int nodataflag = 0;
								int delflag = 0;

								std::map<unsigned int, std::pair<std::string, int> >& indexm = m_indexm[game];
								std::map<unsigned int, std::pair<std::string, int> >::const_iterator itor2 = indexm.find(mindex);
								if (indexm.end() == itor2)
								{
									std::string monthlisttname;
									monthlistTable(game, monthlisttname);
									if (m_monthlistables.end() == m_monthlistables.find(monthlisttname))
									{
										if (!m_dbHandlerAssistant.createMonthListTable(monthlisttname))
										{
											log_error("create monthlist table fail,%s", monthlisttname.c_str());
											rsp.set_result(2);
											break;
										}

										m_monthlistables.emplace(monthlisttname);
									}


									if (m_dbHandlerAssistant.getYmInfoFrommSeq(monthlisttname, mindex, ym, delflag, nodataflag))
									{
										indexm.emplace(mindex, std::make_pair(ym, delflag));
										m_mindex[game][ym] = std::make_pair(mindex, delflag);
									}
									else
									{
										if (1 == nodataflag)
										{
										}
										else
										{
											rsp.set_result(2);
											break;
										}
									}
								}
								else
								{
									ym = itor2->second.first;
									delflag = itor2->second.second;
								}

								unsigned int need = 0;
								if (1 == delflag || 1 == nodataflag)
								{
									rsp.set_result(0);
									rsp.set_endflag(1);
									need = 0;
								}
								else
								{
									need = msg.size() - (itor->second.m_lastflow.size() - dis);
								}

								minuseq = itor1->second.m_userseq;
                                if (need > 0)
                                {
									int ret = fetchRecord(game, ym, mindex, seq, minuseq, uid, need, tt, mr);
									if (2 == ret)
									{
										rsp.set_result(2);
										break;
									}
									else
									{
										rsp.set_result(0);
										if (1 == ret)
										{
											rsp.set_endflag(1);
										}

										if (mr.size() + itor->second.m_lastflow.size() <= g_flow_cache_num)
										{
											itor->second.m_lastflow.insert(mr.begin(), mr.end());
										}
										else
										{
											if (g_flow_cache_num > itor->second.m_lastflow.size())
											{
												unsigned int n = g_flow_cache_num - itor->second.m_lastflow.size();
												if (mr.size() >= n)
												{
													std::map<_u64_, stRecordItem>::reverse_iterator itorend = mr.rbegin();
													::advance(itorend, n);
													itor->second.m_lastflow.insert(mr.rbegin(), itorend);
												}
											}
										}
									}
                                }
							}
							else
							{
								num = msg.size();
							}

							std::map<_u64_, stRecordItem>::reverse_iterator itorbegin = itor->second.m_lastflow.rbegin();
							::advance(itorbegin, dis);
							std::map<_u64_, stRecordItem>::reverse_iterator itorend = itorbegin;
							::advance(itorend, num);
							if (itor->second.m_lastflow.rend() != itorbegin)
							{
								for (std::map<_u64_, stRecordItem>::reverse_iterator itor3 = itorbegin; itorend != itor3; ++itor3)
								{
									if (itor3->second.m_timestamp < recentlisttp)
							        {
								        rsp.set_endflag(1);
								        break;
							        }
									gamerecord::GameRecordResp::GameRecordItem* pitem = rsp.add_list();

									pitem->set_roundid(itor3->second.m_roundid);
									pitem->set_bet(itor3->second.m_bet);
									pitem->set_betact((gamerecord::BET_ACT)itor3->second.m_betact);
									pitem->set_win(itor3->second.m_win);
									pitem->set_winact((gamerecord::WIN_ACT)itor3->second.m_winact);
									pitem->set_timestamp(itor3->second.m_timestamp);
									pitem->set_firstofdayflag(itor3->second.m_firstofdayflag);
									pitem->set_detail(itor3->second.m_detail);
									pitem->set_id(itor3->first);
									pitem->set_ext(itor3->second.m_ext);

									itor3->second.m_lastdetailcachetime = tt;
									if (1 == itor3->second.m_userseq)
									{
										rsp.set_endflag(1);
									}

									unsigned int ymd = 0;
									timestampToymd(itor3->second.m_timestamp, itor->second.m_timezoneinmin, ymd);
									std::map<unsigned int, stRecordDayInfo>::iterator itor4 = itor->second.m_dayinfo.find(ymd);
									if (itor->second.m_dayinfo.end() == itor4)
									{
										itor->second.m_dayinfo.emplace(ymd, stRecordDayInfo(itor3->second.m_daybetamount, itor3->second.m_daywinamount, itor3->second.m_userseq));
									}
									else
									{
										if (itor3->second.m_userseq > itor4->second.m_userseq)
										{
											itor4->second.m_daybetamount = itor3->second.m_daybetamount;
											itor4->second.m_daywinamount = itor3->second.m_daywinamount;
											itor4->second.m_userseq = itor3->second.m_userseq;
										}
									}

									dayset.emplace(ymd);
								}
							}
							//
						}
					}

					for (std::map<_u64_, stRecordItem>::const_reverse_iterator itor3 = mr.rbegin(); mr.rend() != itor3; ++itor3)
					{
						if (itor3->second.m_timestamp < recentlisttp)
						{
							rsp.set_endflag(1);
							break;
						}
						gamerecord::GameRecordResp::GameRecordItem* pitem = rsp.add_list();

						pitem->set_roundid(itor3->second.m_roundid);
						pitem->set_bet(itor3->second.m_bet);
						pitem->set_betact((gamerecord::BET_ACT)itor3->second.m_betact);
						pitem->set_win(itor3->second.m_win);
						pitem->set_winact((gamerecord::WIN_ACT)itor3->second.m_winact);
						pitem->set_timestamp(itor3->second.m_timestamp);
						pitem->set_firstofdayflag(itor3->second.m_firstofdayflag);
						pitem->set_detail(itor3->second.m_detail);
						pitem->set_id(itor3->first);
						pitem->set_ext(itor3->second.m_ext);

						unsigned int ymd = 0;
						timestampToymd(itor3->second.m_timestamp, itor->second.m_timezoneinmin, ymd);
						std::map<unsigned int, stRecordDayInfo>::iterator itor4 = itor->second.m_dayinfo.find(ymd);
						if (itor->second.m_dayinfo.end() == itor4)
						{
							itor->second.m_dayinfo.emplace(ymd, stRecordDayInfo(itor3->second.m_daybetamount, itor3->second.m_daywinamount, itor3->second.m_userseq));
						}
						else
						{
							if (itor3->second.m_userseq > itor4->second.m_userseq)
							{
								itor4->second.m_daybetamount = itor3->second.m_daybetamount;
								itor4->second.m_daywinamount = itor3->second.m_daywinamount;
								itor4->second.m_userseq = itor3->second.m_userseq;
							}
						}

						dayset.emplace(ymd);
					}
				}
			}
			else
			{
				if (0 == msg.pos())
				{
					curYearMonthStr(tt, itor->second.m_timezoneinmin, ym);

					std::map<std::string, std::pair<unsigned int, int> >& mmindex = m_mindex[game];
					std::map<std::string, std::pair<unsigned int, int> >::const_iterator itor2 = mmindex.find(ym);

					int nodataflag = 0;
					int delflag = 0;

					if (mmindex.end() == itor2)
					{
						std::string monthlisttname;
						monthlistTable(game, monthlisttname);
						if (m_monthlistables.end() == m_monthlistables.find(monthlisttname))
						{
							if (!m_dbHandlerAssistant.createMonthListTable(monthlisttname))
							{
								log_error("create monthlist table fail,%s", monthlisttname.c_str());
								rsp.set_result(2);
								break;
							}

							m_monthlistables.emplace(monthlisttname);
						}

						if (m_dbHandlerAssistant.getYmInfo(monthlisttname, ym, mindex, delflag, nodataflag))
						{
							mmindex.emplace(ym, std::make_pair(mindex, delflag));
							m_indexm[game][mindex] = std::make_pair(ym, delflag);
						}
						else
						{
							if (1 == nodataflag)
							{
								if (m_dbHandlerAssistant.getLastMonth(monthlisttname, ym, mindex, delflag, nodataflag))
								{
									mmindex.emplace(ym, std::make_pair(mindex, delflag));
									m_indexm[game][mindex] = std::make_pair(ym, delflag);
								}
								else
								{
									if (1 == nodataflag)
									{
									}
									else
									{
										rsp.set_result(2);
										break;
									}
								}
							}
							else
							{
								rsp.set_result(2);
								break;
							}
						}

					}
					else
					{
						mindex = itor2->second.first;
						delflag = itor2->second.second;
					}

					unsigned int need = 0;
					if (1 == delflag || 1 == nodataflag)
					{
						rsp.set_result(0);
						rsp.set_endflag(1);
						need = 0;
					}
					else
					{
						need = msg.size();
					}


					if (mindex > 0 && need > 0)
					{
						std::map<_u64_, stRecordItem> mr;
						int ret = fetchRecord(game, ym, mindex, seq, itor->second.m_count, uid, need, tt, mr);
						if (2 == ret)
						{
							rsp.set_result(2);
							break;
						}
						else
						{
							rsp.set_result(0);
							if (1 == ret)
							{
								rsp.set_endflag(1);
							}

							if (mr.size() + itor->second.m_lastflow.size() <= g_flow_cache_num)
							{
								itor->second.m_lastflow.insert(mr.begin(), mr.end());
							}
							else
							{
								if (g_flow_cache_num > itor->second.m_lastflow.size())
								{
									unsigned int n = g_flow_cache_num - itor->second.m_lastflow.size();
									if (mr.size() >= n)
									{
										std::map<_u64_, stRecordItem>::reverse_iterator itorend = mr.rbegin();
										::advance(itorend, n);
										itor->second.m_lastflow.insert(mr.rbegin(), itorend);
									}
								}
							}

							for (std::map<_u64_, stRecordItem>::reverse_iterator itor3 = mr.rbegin(); mr.rend() != itor3; ++itor3)
							{
								if (itor3->second.m_timestamp < recentlisttp)
							   {
								    rsp.set_endflag(1);
								    break;
							    }
								gamerecord::GameRecordResp::GameRecordItem* pitem = rsp.add_list();

								pitem->set_roundid(itor3->second.m_roundid);
								pitem->set_bet(itor3->second.m_bet);
								pitem->set_betact((gamerecord::BET_ACT)itor3->second.m_betact);
								pitem->set_win(itor3->second.m_win);
								pitem->set_winact((gamerecord::WIN_ACT)itor3->second.m_winact);
								pitem->set_timestamp(itor3->second.m_timestamp);
								pitem->set_firstofdayflag(itor3->second.m_firstofdayflag);
								pitem->set_detail(itor3->second.m_detail);
								pitem->set_id(itor3->first);
								pitem->set_ext(itor3->second.m_ext);
								itor3->second.m_lastdetailcachetime = tt;

								unsigned int ymd = 0;
								timestampToymd(itor3->second.m_timestamp, itor->second.m_timezoneinmin, ymd);
								std::map<unsigned int, stRecordDayInfo>::iterator itor4 = itor->second.m_dayinfo.find(ymd);
								if (itor->second.m_dayinfo.end() == itor4)
								{
									itor->second.m_dayinfo.emplace(ymd, stRecordDayInfo(itor3->second.m_daybetamount, itor3->second.m_daywinamount, itor3->second.m_userseq));
								}
								else
								{
									if (itor3->second.m_userseq > itor4->second.m_userseq)
									{
										itor4->second.m_daybetamount = itor3->second.m_daybetamount;
										itor4->second.m_daywinamount = itor3->second.m_daywinamount;
										itor4->second.m_userseq = itor3->second.m_userseq;
									}
								}

								dayset.emplace(ymd);
							}

						}
					}
				}
				else
				{
					_u64_ indexpos = msg.pos();
					mindex = (indexpos & 0xFFFF000000000000) >> 48;
					seq = indexpos & 0x0000FFFFFFFFFFFF;

					int nodataflag = 0;
					int delflag = 0;

					std::map<unsigned int, std::pair<std::string, int> >& indexm = m_indexm[game];
					std::map<unsigned int, std::pair<std::string, int> >::const_iterator itor2 = indexm.find(mindex);
					if (indexm.end() == itor2)
					{
						std::string monthlisttname;
						monthlistTable(game, monthlisttname);
						if (m_monthlistables.end() == m_monthlistables.find(monthlisttname))
						{
							if (!m_dbHandlerAssistant.createMonthListTable(monthlisttname))
							{
								log_error("create monthlist table fail,%s", monthlisttname.c_str());
								rsp.set_result(2);
								break;
							}

							m_monthlistables.emplace(monthlisttname);
						}


						if (m_dbHandlerAssistant.getYmInfoFrommSeq(monthlisttname, mindex, ym, delflag, nodataflag))
						{
							indexm.emplace(mindex, std::make_pair(ym, delflag));
							m_mindex[game][ym] = std::make_pair(mindex, delflag);
						}
						else
						{
							if (1 == nodataflag)
							{
								ym = "";
							}
							else
							{
								rsp.set_result(2);
								break;
							}
						}
					}
					else
					{
						ym = itor2->second.first;
						delflag = itor2->second.second;
					}

					unsigned int need = 0;
					if (1 == delflag)
					{
						rsp.set_result(0);
						rsp.set_endflag(1);
						need = 0;
					}
					else
					{
						need = msg.size();
					}

					if (!ym.empty() && need > 0)
					{
						std::map<_u64_, stRecordItem> mr;
						int ret = fetchRecord(game, ym, mindex, seq, itor->second.m_count, uid, need, tt, mr);
						if (2 == ret)
						{
							rsp.set_result(2);
							break;
						}
						else
						{
							rsp.set_result(0);
							if (1 == ret)
							{
								rsp.set_endflag(1);
							}

							for (std::map<_u64_, stRecordItem>::const_reverse_iterator itor3 = mr.rbegin(); mr.rend() != itor3; ++itor3)
							{
								if (itor3->second.m_timestamp < recentlisttp)
							    {
								    rsp.set_endflag(1);
								    break;
							    }
								gamerecord::GameRecordResp::GameRecordItem* pitem = rsp.add_list();

								pitem->set_roundid(itor3->second.m_roundid);
								pitem->set_bet(itor3->second.m_bet);
								pitem->set_betact((gamerecord::BET_ACT)itor3->second.m_betact);
								pitem->set_win(itor3->second.m_win);
								pitem->set_winact((gamerecord::WIN_ACT)itor3->second.m_winact);
								pitem->set_timestamp(itor3->second.m_timestamp);
								pitem->set_firstofdayflag(itor3->second.m_firstofdayflag);
								pitem->set_detail(itor3->second.m_detail);
								pitem->set_id(itor3->first);
								pitem->set_ext(itor3->second.m_ext);

								unsigned int ymd = 0;
								timestampToymd(itor3->second.m_timestamp, itor->second.m_timezoneinmin, ymd);
								std::map<unsigned int, stRecordDayInfo>::iterator itor4 = itor->second.m_dayinfo.find(ymd);
								if (itor->second.m_dayinfo.end() == itor4)
								{
									itor->second.m_dayinfo.emplace(ymd, stRecordDayInfo(itor3->second.m_daybetamount, itor3->second.m_daywinamount, itor3->second.m_userseq));
								}
								else
								{
									if (itor3->second.m_userseq > itor4->second.m_userseq)
									{
										itor4->second.m_daybetamount = itor3->second.m_daybetamount;
										itor4->second.m_daywinamount = itor3->second.m_daywinamount;
										itor4->second.m_userseq = itor3->second.m_userseq;
									}
								}

								dayset.emplace(ymd);
							}
						}
					}
				}
			}

			for (std::set<unsigned int>::const_reverse_iterator itor2 = dayset.rbegin(); dayset.rend() != itor2; ++itor2)
			{
				std::map<unsigned int, stRecordDayInfo>::const_iterator itor3 = itor->second.m_dayinfo.find(*itor2);
				if (itor->second.m_dayinfo.end() != itor3)
				{
					gamerecord::GameRecordResp::DayAmountItem* pitem = rsp.add_daylist();

					pitem->set_year(itor3->first/10000);
					pitem->set_month((itor3->first % 10000)/100);
					pitem->set_day(itor3->first % 100);
					pitem->set_betamount(itor3->second.m_daybetamount);
					pitem->set_winamount(itor3->second.m_daywinamount);
				}
			}
		}

		rsp.set_totalsize(itor->second.m_count);
	} while (false);


	if (!msg.trans().empty())
	{
		rsp.set_trans(msg.trans());
	}

	if (SERVER_TYPE_AGENT == pHandler->getType())//客户端消息
	{
		m_pHost->SendPlayerPb(pHandler, gamerecord::GAMERECORD_CMD_GET_RECORD_RESP, uid, &rsp);
		log_debug("getrecord rsp,agent,uid,%u,game,%u",uid,game);
	}
	else
	{
		m_pHost->SendPb(pHandler, gamerecord::GAMERECORD_CMD_GET_RECORD_RESP, pHandler->getType(), pHandler->getId(), &rsp);
		log_debug("getrecord rsp,uid,%u,game,%u",uid,game);
	}

	return 0;
}

int CGameServer::ProcGetGameRecordDetail(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	gamerecord::GameRecordDetailReq msg;
	if (!inputPkg->parsePb(&msg))
	{
		log_error("parse pb fail");
		return 1;
	}

	unsigned int uid = msg.uid();
	unsigned int game = msg.game();
	_u64_ id = msg.id();
	gamerecord::GameRecordDetailResp rsp;
	do 
	{
		if (0 == uid || 0 == game || 0 == id)
		{
			rsp.set_result(1);
			break;
		}
		rsp.set_uid(uid);
		rsp.set_game(game);
		rsp.set_id(id);

		std::map<unsigned int, stRecordCache>& gamerecordcache = m_recordcache[game];
		std::map<unsigned int, stRecordCache>::iterator itor = gamerecordcache.find(uid);
		std::map<_u64_, stRecordItem>::iterator itor1;
		bool itorvalid = false;
		if (gamerecordcache.end() != itor)
		{
			itor1 = itor->second.m_lastflow.find(id);
			if (itor->second.m_lastflow.end() != itor1)
			{
				itorvalid = true;
				if (!itor1->second.m_detail.empty())
				{
					rsp.set_detail(itor1->second.m_detail);
					rsp.set_result(0);
					break;
				}
			}
		}

		std::string ym;
		unsigned int mindex = (id & 0xFFFF000000000000) >> 48;
		_u64_ seq = id & 0x0000FFFFFFFFFFFF;

		std::map<unsigned int, std::pair<std::string, int> >& indexm = m_indexm[game];
		std::map<unsigned int, std::pair<std::string, int> >::const_iterator itor2 = indexm.find(mindex);
		if (indexm.end() == itor2)
		{
			std::string monthlisttname;
			monthlistTable(game, monthlisttname);
			if (m_monthlistables.end() == m_monthlistables.find(monthlisttname))
			{
				if (!m_dbHandlerAssistant.createMonthListTable(monthlisttname))
				{
					log_error("create monthlist table fail,%s", monthlisttname.c_str());
					rsp.set_result(2);
					break;
				}

				m_monthlistables.emplace(monthlisttname);
			}

			int nodataflag = 0;
			int delflag = 0;
			if (m_dbHandlerAssistant.getYmInfoFrommSeq(monthlisttname, mindex, ym, delflag, nodataflag))
			{
				indexm.emplace(mindex, std::make_pair(ym, delflag));
				m_mindex[game][ym] = std::make_pair(mindex, delflag);
			}
			else
			{
				if (1 == nodataflag)
				{
					ym = "";
				}
				else
				{
					rsp.set_result(2);
					break;
				}
			}
		}
		else
		{
			ym = itor2->second.first;
		}

		if (ym.empty())
		{
			rsp.set_result(1);
			break;
		}

		std::string recordtname;
		tableName(game, ym, uid, g_uid_mod, recordtname);
		std::set<std::string>::const_iterator itor3 = m_recordtables.find(recordtname);
		if (m_recordtables.end() == itor3)
		{
			if (!m_dbHandler.createRecordTable(recordtname))
			{
				log_error("add table fail,%s", recordtname.c_str());
				rsp.set_result(2);
				break;
			}
			m_recordtables.emplace(recordtname);

			if (!m_dbHandlerMaintenance.addTableRecord(recordtname, game, ::atoi(ym.c_str()), uid%g_uid_mod, ::time(NULL)))
		    {
			    log_error("record table fail,%s", recordtname.c_str());
		    }	
		}

		std::string detail;
		int nodataflag = 0;
		if (!m_dbHandler.getRecordDetail(recordtname, seq, uid, detail, nodataflag))
		{
			rsp.set_result(2);
			break;
		}
		if (1 == nodataflag)
		{
			rsp.set_result(1);
			break;
		}

		rsp.set_detail(detail);
		rsp.set_result(0);

		if (itorvalid)
		{
			itor1->second.m_detail = detail;
			itor1->second.m_lastdetailcachetime = ::time(NULL);
		}
	} while (false);


	if (SERVER_TYPE_AGENT == pHandler->getType())//客户端消息
	{
		m_pHost->SendPlayerPb(pHandler, gamerecord::GAMERECORD_CMD_GET_DETAIL_RESP, uid, &rsp);
	}
	else
	{
		m_pHost->SendPb(pHandler, gamerecord::GAMERECORD_CMD_GET_DETAIL_RESP, pHandler->getType(), pHandler->getId(), &rsp);
	}
}

int CGameServer::fetchRecord(const unsigned int game, const std::string& startym, const unsigned int mseq, const _u64_ startseq, const unsigned int minuseq, const unsigned int uid, const unsigned int reqnum, const _u64_ lasttime, std::map<_u64_, stRecordItem>& record)
{
	unsigned int tmseq = mseq;
	unsigned int tuseq = minuseq;
	unsigned int treqnum = reqnum;
	_u64_ tstartseq = startseq;
	std::string tstartym = startym;
	bool fetchtball = false;
	while (tmseq >= 1 && tuseq > 1 && treqnum > 0)
	{
		std::string recordtname;
		int delflag = 0;
		int nodataflag = 0;

        std::map<unsigned int, std::pair<std::string, int> >& indexm = m_indexm[game];
		std::map<unsigned int, std::pair<std::string, int> >::const_iterator itor = indexm.find(tmseq);
		if (indexm.end() == itor || tstartym.empty())
		{
			std::string monthlisttname;
			monthlistTable(game, monthlisttname); 
	        if (m_monthlistables.end() == m_monthlistables.find(monthlisttname))
	        {
		        if (!m_dbHandlerAssistant.createMonthListTable(monthlisttname))
		        {
			        log_error("create monthlist table fail,%s", monthlisttname.c_str());
					return 2;
		        }
		
		        m_monthlistables.emplace(monthlisttname);
	        }

			if (m_dbHandlerAssistant.getYmInfoFrommSeq(monthlisttname, tmseq, tstartym, delflag, nodataflag))
			{
				indexm.emplace(tmseq, std::make_pair(tstartym, delflag));
				m_mindex[game][tstartym] = std::make_pair(tmseq, delflag);				
			}
			else
			{
				if (1 == nodataflag)
				{
					--tmseq;
					tstartseq = 0;
					continue;
					//return 1;
				}
				else
				{
					return 2;
				}
			}
		}
		else
		{
			tstartym = itor->second.first;
			delflag = itor->second.second;
		}

		if (1 == delflag)
		{
			return 1;
		}

        tableName(game, tstartym, uid, g_uid_mod, recordtname);
	    std::set<std::string>::const_iterator itor1 = m_recordtables.find(recordtname);
	    if (m_recordtables.end() == itor1)
	    {
		    if (!m_dbHandler.createRecordTable(recordtname))
		    {
			    log_error("add table fail,%s", recordtname.c_str());
			    return 2;
		    }
		    m_recordtables.emplace(recordtname);

			if (!m_dbHandlerMaintenance.addTableRecord(recordtname, game, ::atoi(tstartym.c_str()), uid%g_uid_mod, ::time(NULL)))
		    {
			    log_error("record table fail,%s", recordtname.c_str());
		    }	
	    }

		std::map<_u64_, stRecordItem> mr;
		if (!m_dbHandler.getRecord(recordtname, tstartseq, uid, treqnum, mr))
		{
			return 2;
		}

		if (mr.size() < treqnum)
		{
			fetchtball = true;//already fetch all data of one table
		}
		else
		{
			fetchtball = false;
		}

		for (std::map<_u64_, stRecordItem>::iterator itor2 = mr.begin(); mr.end() != itor2; ++itor2)
		{
			_u64_ index = (((_u64_)tmseq << 48) | itor2->first);
			itor2->second.m_lastdetailcachetime = lasttime;
			record.emplace(index, itor2->second);
			if (itor2->second.m_userseq < tuseq)
			{
				tuseq = itor2->second.m_userseq;
			}
		}

		--tmseq;
		if (mr.size() <= treqnum)
			treqnum -= mr.size();
		else
			treqnum = 0;

		tstartseq = 0;
	}

	if (1 == tuseq)
	{
		return 1;//已查询到底
	}
	if (tmseq == 0 && fetchtball)
	{
		return 1;//已查询到底
	}

	return 0;

}

int CGameServer::ProcEventGameInit(int ev_id, SpiderEvent* pEvent)
{
	StartTimer(TIMERID_CACHE_CHECK, g_cache_check_dur, true);
	StartTimer(TIMERID_DETAIL_CACHE_CHECK, g_detail_cache_check_dur, true);

	return 0;
}

int CGameServer::procTimerCacheCheck(void)
{
	time_t tt = ::time(NULL);
	for (std::map<unsigned int, std::map<unsigned int, stRecordCache> >::iterator itor = m_recordcache.begin(); m_recordcache.end() != itor; ++itor)
	{
		for (std::map<unsigned int, stRecordCache>::iterator itor1 = itor->second.begin(); itor->second.end() != itor1; )
		{
			if (tt - itor1->second.m_lastfetchtime > g_cache_dur && tt - itor1->second.m_lastflowtime > g_cache_dur)
			{
				itor->second.erase(itor1++);
			}
			else
			{
				++itor1;
			}
		}
	}
}

int CGameServer::procTimerDetailCacheCheck(void)
{
	time_t tt = ::time(NULL);
	for (std::map<unsigned int, std::map<unsigned int, stRecordCache> >::iterator itor = m_recordcache.begin(); m_recordcache.end() != itor; ++itor)
	{
		for (std::map<unsigned int, stRecordCache>::iterator itor1 = itor->second.begin(); itor->second.end() != itor1; ++itor1)
		{
			for (std::map<_u64_, stRecordItem>::iterator itor2 = itor1->second.m_lastflow.begin(); itor1->second.m_lastflow.end() != itor2; ++itor2)
			{
				if (!itor2->second.m_detail.empty())
				{
					if (tt - itor2->second.m_lastdetailcachetime > g_detail_cache_dur)
					{
						std::string().swap(itor2->second.m_detail);
					}
				}
			}
		}
	}
}

void CGameServer::gamerecordCountTable(const unsigned int game, const unsigned int mod, const unsigned int uid, std::string& tablename)
{
	char name[64] = { 0 };
	::snprintf(name, sizeof(name)-1, "user_gamerecord_count_%u_%u", game, (uid%mod));
	tablename = name;

	return;
}

void CGameServer::monthlistTable(const unsigned int game, std::string& tablename)
{
	char name[64] = { 0 };
	::snprintf(name, sizeof(name)-1, "month_list_%u", game);
	tablename = name;

	return;
}